SMTP(简单邮件传输协议)协议学习(Wireshark分析&C语言解析)

您所在的位置:网站首页 电子邮件使用的传输协议是( ) SMTP(简单邮件传输协议)协议学习(Wireshark分析&C语言解析)

SMTP(简单邮件传输协议)协议学习(Wireshark分析&C语言解析)

2024-07-16 22:46:32| 来源: 网络整理| 查看: 265

一、基础知识 协议简介

SMTP (Simple Mail Transfer Protocol)是一种用于电子邮件传输的协议,它定义了如何在网络上传输和路由邮件。SMTP协议通常与POP3或IMAP协议一起使用,以实现电子邮件的发送和接收.它的底层原理主要是通过TCP建立可靠的连接,使用命令和响应模式来传输邮件。SMTP服务器通常监听TCP端口25,SMTP客户端使用这个端口与服务器建立连接,然后进行邮件传输。

命令和错误码

SMTP协议定义了一系列的命令和错误码,用于在电子邮件传输过程中进行通信和错误处理,状态码在200-300之间都是正确的,只是代表的涵义不一样下面是一些常见的SMTP命令和状态码:

SMTP命令

命令

作用

HELO/EHLO

发送方向服务器发送问候命令,以建立SMTP连接

MAIL FROM

指定发件人地址

RCPT TO

指定收件人地址

DATA

指示邮件正文的开始

QUIT

关闭与服务器的SMTP连接

状态码

状态码

涵义

211

系统状态或系统帮助响应

214

帮助信息

220

服务就绪

221

服务关闭传输通道

250

请求的操作完成

251

用户非本地,将转发到

354

开始邮件输入

421

服务未就绪,关闭传输信道。

450

请求的操作未完成,可能会再次尝试

451

请求的操作中止:错误处理中发生局部故障

452

请求的操作未执行,系统存储空间不足

500

语法错误,命令无法识别

501

参数语法错误

502

命令不可执行

503

错误的命令序列

504

命令参数不可识别

550

请求的操作未完成,信箱不可用(例如,不存在,无法访问)

551

用户非本地,请尝试

552

请求操作超出存储分配

553

请求的操作未完成,邮箱名不可用(例如,格式错误)

通信流程

1.建立连接:客户端使用TCP连接到SMTP服务器的25号端口。在连接成功后,客户端向服务器发送HELO命令,以表示自己的身份和意图。

2.发送发件人信息:客户端使用MAIL FROM命令指定发件人的电子邮件地址。如果发件人地址无效,则服务器会返回错误码并中止传输。

3.发送收件人信息:客户端使用RCPT TO命令指定一个或多个收件人的电子邮件地址。如果收件人地址无效,则服务器会返回错误码并中止传输。

4.发送邮件内容:客户端使用DATA命令指定邮件文本内容,以及包含的附件等信息。数据通常以点号(.)结束。

5.退出连接:当所有邮件内容都已发送后,客户端使用QUIT命令结束SMTP会话并断开连接。

协议优点

1.可靠性高:使用TCP建立可靠的连接,保证数据传输的可靠性。

2.灵活性强:支持扩展命令,可以根据需要定制邮件传输的方式。

3.通用性强:被广泛使用于电子邮件系统中。

二、Wireshark分析

下载安装Foxmail工具,这里我是登录的qq邮箱

选择账号管理->账号->取消SSL勾选(这里一定要取消勾选,否则抓取不到SMTP的数据包)

数据包分析

Wireshark查看SMTP数据包捕获情况

追踪SMTP数据包TCP流,逐个分析

服务器返回了一系列信息,包括服务器名称、PIPELINING(表示服务器支持命令的串行执行)、邮件大小限制、STARTTLS(表示服务器支持加密连接)、认证方式等。在发送邮件之前,这个特征协商过程会发生在每次SMTP传输的开始部分。

邮件传输从SMTP数据包的第4个数据包开始,这个抓包文件的剩余的大部分均为邮件传输过程的数据包。

数据包4发送了一条AUTH XOAUTH2命令,表示要使用XOAUTH2方式进行认证。这是一种基于OAuth 2.0的安全认证方式,用于授权第三方应用访问用户的邮件账户。

接着服务器返回了"235 2.7.0 Accepted",表示认证成功。

接下来客户端发送了一条MAIL FROM命令,表示发件人地址,并包含邮件大小信息,服务器返回"250 OK",表示发件人地址验证通过。

客户端接着发送了一条RCPT TO命令,表示收件人地址,服务器同样返回"250 OK",表示收件人地址验证通过。

紧接着客户端发送了DATA命令,表示即将发送邮件内容,服务器返回"354 End data with ..",表示可以开始发送邮件内容,并告知结束标志为.。

该部分,主要是包含日期、发件人、收件人、主题、邮件优先级、消息ID等信息的邮件内容,以及以multipart/alternative格式包含的纯文本和HTML格式的邮件正文内容。

服务器返回"250 OK: queued as.",表示该封邮件已成功入队等待发送,表明整个邮件发送过程顺利完成

最后,客户端发送了QUIT命令,表示断开连接。服务器返回"221 Bye.",表示成功断开连接。

分析验证

打开我们最开始发送的邮件,查看相关信息

解码邮件正文内容

可以看到这些信息与我们刚才所分析出来的信息全部一致。

三、C语言实现

注:这里代码解析的邮件与上面Wireshark解析的邮件是不一样的,所以邮件内容不是一样的!!!

运行结果

环境配置

配置文件

一共有五个文件需要导入,这五个文件内容可以直接在网络协议分析(二)(C语言实现---ethernet、arp、ip、icmp、udp、tcp 完整代码)_c语言实现arp-CSDN博客文章里面复制。

主文件

注:里面涉及到离线文件路径的地方需要修改为自己的

#include #include #include #include #include // 添加头文件 #include #include #include #include #include #include void extract_email_info(const char *content); int ip_printed = 0; int content_printed = 0; // 标记是否已经输出过Content void smtp_protocol_callback(struct tcp_stream *smtp_connection, void **arg) { int i; char ascii_string[10000]; switch(smtp_connection->nids_state) { case NIDS_JUST_EST: if (smtp_connection->addr.dest == 25) { smtp_connection->client.collect++; smtp_connection->server.collect++; smtp_connection->server.collect_urg++; smtp_connection->client.collect_urg++; } return; case NIDS_CLOSE: return; case NIDS_RESET: return; case NIDS_DATA: { struct half_stream *hlf; if (smtp_connection->client.count_new) { hlf = &smtp_connection->client; } else if (smtp_connection->server.count_new) { hlf = &smtp_connection->server; } else { return; } memcpy(ascii_string, hlf->data, hlf->count_new); ascii_string[hlf->count_new] = '\0'; extract_email_info(ascii_string); if (!ip_printed) { char src_ip[16], dest_ip[16]; inet_ntop(AF_INET, &(smtp_connection->addr.saddr), src_ip, 16); inet_ntop(AF_INET, &(smtp_connection->addr.daddr), dest_ip, 16); printf("Source IP: %s\n", src_ip); printf("Dest IP: %s\n", dest_ip); printf("Port: %d\n", smtp_connection->addr.dest); ip_printed = 1; } } default: break; } } void extract_email_info(const char *content) { const char *tmp; char from[1000] = {0}; char to[1000] = {0}; // 提取"From:"字段 const char *tmp1; tmp1 = strstr(content, "From: "); if (tmp1 != NULL) { const char *start = strchr(tmp1, ''); // 查找 ">" if (start != NULL && end != NULL) { printf("From: %.*s\n", end - (start + 1), start + 1); } } // 提取"To:"字段 tmp = strstr(content, "To: "); if (tmp != NULL) { const char *start = strchr(tmp, ''); // 查找 ">" if (start != NULL && end != NULL) { size_t length = end - (start + 1); char address[length + 1]; // 新建一个足够容纳邮件地址的字符数组 strncpy(address, start + 1, length); // 拷贝邮件地址到新的字符数组中 address[length] = '\0'; // 添加结尾的空字符 printf("To: %s\n", address); } } tmp = strstr(content, "Subject:"); if (tmp != NULL) { char subject[1000] = {0}; sscanf(tmp + 8, "%[^\r\n]", subject); printf("Subject: %s\n", subject); } int is_content = 0; int content_printed = 0; const char *content_type = strstr(content, "Content-Type: "); if (content_type != NULL) { if (strstr(content_type, "text/plain") || strstr(content_type, "text/html")) { is_content = 1; } } tmp = strstr(content, "\r\n\r\n"); while (tmp != NULL) { if (!content_printed && is_content) { printf("Content: "); content_printed = 1; } if (is_content) { // Base64解密 BIO *bio, *b64; BUF_MEM *bufferPtr; b64 = BIO_new(BIO_f_base64()); bio = BIO_new_mem_buf((void *)tmp, -1); bio = BIO_push(b64, bio); // 解密并输出 char decoded_content[10000]; int length = BIO_read(bio, decoded_content, sizeof(decoded_content)); if (length > 0) { decoded_content[length] = '\0'; // 添加结尾的空字符 printf("%s\n", decoded_content); break; // 解密一次后退出循环 } BIO_free_all(bio); } tmp = strstr(tmp + 4, "\r\n\r\n"); // 继续搜索下一个附件或正文内容的起始位置 } // 提取附件标题和内容 tmp = strstr(content, "\r\n\r\n"); if (tmp != NULL) { tmp = strstr(tmp + 4, "Content-Disposition: attachment"); if (tmp != NULL) { const char *filename_start = strstr(tmp, "filename=\""); const char *filename_end = strstr(filename_start + 10, "\""); if (filename_start != NULL && filename_end != NULL) { //printf("Attachment Title: %.*s\n", (int)(filename_end - (filename_start + 10)), filename_start + 10); const char *attachment_content_start = strstr(tmp, "\r\n\r\n") + 4; const char *attachment_content_end = strstr(attachment_content_start, "\r\n--"); if (attachment_content_start != NULL && attachment_content_end != NULL) { //printf("Attachment Content: "); // Base64解密 BIO *bio2, *b64_2; BUF_MEM *bufferPtr2; b64_2 = BIO_new(BIO_f_base64()); bio2 = BIO_new_mem_buf((void *)attachment_content_start, -1); bio2 = BIO_push(b64_2, bio2); // 解密并输出 char decoded_attachment[20000]; // 增加缓冲区大小 memset(decoded_attachment, 0, sizeof(decoded_attachment)); // 初始化为全0 int length2 = BIO_read(bio2, decoded_attachment, sizeof(decoded_attachment) - 1); if (length2 > 0) { decoded_attachment[length2] = '\0'; // 在解密后的内容末尾添加终止符 //printf("%s\n", decoded_attachment); // 直接输出解密后的内容 // 将解密后的附件内容写入文件 const char *attachment_title = filename_start + 10; size_t attachment_length = filename_end - attachment_title; char attachment_filename[attachment_length + 1]; strncpy(attachment_filename, attachment_title, attachment_length); attachment_filename[attachment_length] = '\0'; char filepath[100]; sprintf(filepath, "/home/gxy/work/project-smtp/Debug/%s", attachment_filename); FILE *fp = fopen(filepath, "w"); if (fp != NULL) { fwrite(decoded_attachment, sizeof(char), strlen(decoded_attachment), fp); fclose(fp); } } BIO_free_all(bio2); } } } } } int main() { dictionary* ini = iniparser_load("/home/gxy/work/project-smtp/conf.ini"); int method = iniparser_getint(ini, "Method:Method", 0); const char* net_interface = iniparser_getstring(ini, "Interface:Interface", "NULL"); const char* fname = iniparser_getstring(ini, "OpenPath:Fname", "/home/gxy/work/project-smtp/Debug/smtp.pcap"); struct nids_chksum_ctl op; op.mask = 0; op.netaddr = 0; op.action = NIDS_DONT_CHKSUM; nids_register_chksum_ctl(&op, 1); if (method == 1) { nids_params.device = net_interface; nids_params.filename = 0; } else { nids_params.device = 0; nids_params.filename = fname; } if (0 == nids_init()) { printf("params is error: %s\n", nids_errbuf); return 0; } nids_register_tcp(smtp_protocol_callback); nids_run(); return 0; }


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭